package com.qingcheng.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.qingcheng.dao.BrandMapper;
import com.qingcheng.dao.SpecMapper;
import com.qingcheng.pojo.goods.Category;
import com.qingcheng.service.goods.CategoryService;
import com.qingcheng.service.goods.SkuSearchService;
import com.qingcheng.utils.CacheKey;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;


import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by yuanxin
 * Date:2019/7/7
 * Time:12:11
 */
@Service
public class SkuSearchServiceImpl implements SkuSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private BrandMapper brandMapper;
    @Autowired
    private SpecMapper specMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CategoryService categoryService;

    @Override
    public Map search(Map<String, String> searchMap) {
        //封装查询请求
        SearchRequest searchRequest = new SearchRequest("sku");
        searchRequest.types("doc");//设置查询的类型

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //布尔查询构建器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //1.1关键字搜索
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", searchMap.get("keywords"));
        boolQueryBuilder.must(matchQueryBuilder);
        //1.2商品分类过滤
        if (searchMap.get("category") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //1.3品牌过滤
        if (searchMap.get("brand") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //规格过滤
        for (String key : searchMap.keySet()) {
            if (key.startsWith("spec.")) {
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key + ".keyword", searchMap.get(key));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }
        //价格过滤
        if (searchMap.get("price") != null) {
            String[] prices = searchMap.get("price").split("-");
            if (!"0".equals(prices[0])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(prices[0] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if (!"*".equals(prices[1])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").lte(prices[1] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
        }
        searchSourceBuilder.query(boolQueryBuilder);
        //分页
        Integer pageNo = Integer.parseInt(searchMap.get("pageNo"));//当前页码
        Integer pageSize = CacheKey.Size;//每页显示条数
        //起始记录下标
        int fromIndex = (pageNo - 1) * pageSize;
        searchSourceBuilder.from(fromIndex);
        searchSourceBuilder.size(pageSize);
        //排序
        String sort = searchMap.get("sort");
        String sortOrder = searchMap.get("sortOrder");
        if (!"".equals(sort)) {
            searchSourceBuilder.sort(sort, SortOrder.valueOf(sortOrder));
        }

        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //聚合查询(分组查询商品分类)
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName");
        searchSourceBuilder.aggregation(termsAggregationBuilder);


        searchRequest.source(searchSourceBuilder);


        //封装查询结果
        Map resultMap = new HashMap();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            long totalHits = searchHits.getTotalHits();
            System.out.println("记录数:" + totalHits);
            SearchHit[] hits = searchHits.getHits();

            //商品列表
            List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
            for (SearchHit hit : hits) {
                Map<String, Object> skuMap = hit.getSourceAsMap();
                //提取高亮内容
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightFieldName = highlightFields.get("name");

                Text[] fragments = highlightFieldName.fragments();
                skuMap.put("name",fragments[0].toString());


                resultList.add(skuMap);
            }
            resultMap.put("rows", resultList);

            //商品分类
            List<String> categoryList = new ArrayList<>();
            if (searchMap.get("category") == null) {
                Aggregations aggregations = searchResponse.getAggregations();
                Map<String, Aggregation> map = aggregations.getAsMap();
                Terms skuCategory = (Terms) map.get("sku_category");

                List<? extends Terms.Bucket> buckets = skuCategory.getBuckets();
                for (Terms.Bucket bucket : buckets) {
                    categoryList.add(bucket.getKeyAsString());
                }
                resultMap.put("categoryList", categoryList);
            }

            //品牌列表
            String categoryName = "";//商品分类名称\
            Map map = null;
            if (searchMap.get("brand") == null) {
                if (searchMap.get("category") == null) {//如果没有分类条件
                    if (categoryList.size() > 0) {
                        categoryName = categoryList.get(0);//提取分类列表中的第一个参数
                    }
                } else {
                    categoryName = searchMap.get("category");//取出参数中分类
                }
//                List<Map> brandList = brandMapper.findListByCategoryName(categoryName);
                map = (Map) redisTemplate.boundHashOps(CacheKey.BRANDANDSPECLIST).get(categoryName);//查询品牌列表
                List<Map> brandList = new ArrayList<>();
                if (map != null) {
                    brandList = (List<Map>) map.get("brandList");
                }
                resultMap.put("brandList", brandList);
            }

            //规格列表
//            List<Map> specList = specMapper.findListByCategoryName(categoryName);
            List<Map> specList = new ArrayList<>();
            if (map != null) {
                specList = (List<Map>) map.get("specList");
            }
            for (Map spec : specList) {
                String[] options = ((String) spec.get("options")).split(",");
                spec.put("options", options);
            }
            resultMap.put("specList", specList);


            //计算总页数
            Long totalCount = (totalHits % pageSize == 0) ? (totalHits / pageSize) : (totalHits / pageSize + 1);
            Integer totalPages = totalCount.intValue();
            resultMap.put("totalPages",totalPages);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    public void saveAllBrandAndSpecListByCategoryToRedis() {
        if (!redisTemplate.hasKey(CacheKey.BRANDANDSPECLIST)) {
            System.out.println("加载商品分类和品牌规格进缓存");
            List<Category> categoryList = categoryService.findAll();
            Map<String, List<Map>> map = new HashMap<>();
            for (Category category : categoryList) {
                List<Map> brandList = brandMapper.findListByCategoryName(category.getName());
                List<Map> specList = specMapper.findListByCategoryName(category.getName());
                map.put("brandList", brandList);
                map.put("specList", specList);
                redisTemplate.boundHashOps(CacheKey.BRANDANDSPECLIST).put(category.getName(), map);
            }
        }
    }
}
